package com.frank.loadinglibrary.special.element;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import com.frank.loadinglibrary.utils.SimpleAnimatorListener;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class SlackLoadingElement extends BaseElement implements BaseAnimationController.IAnimationController<Animator> {


    /**
     * 静止状态
     */
    private static final int STATUS_STILL = 0;

    /**
     * 加载状态
     */
    private static final int STATUS_LOADING = 1;

    /**
     * 线条最短长度
     */
    private static final int MIN_LINE_LENGTH = 40;

    /**
     * 最小间隔时长
     */
    private final int MIN_DURATION = 1000;

    private Paint mPaint;

    private int[] mColors = new int[]{0xB07ECBDA, 0xB0E6A92C, 0xB0D6014D, 0xB05ABA94};

    private float mWidth;
    private float mHeight;

    /**
     * 动画间隔时长
     */
    private int mDuration = MIN_DURATION;

    /**
     * 线条总长度
     */
    private int mEntireLineLength = MIN_LINE_LENGTH;

    /**
     * 圆半径
     */
    private int mCircleRadius;

    /**
     * 所有动画
     */
    private List<Animator> mAnimList = new ArrayList<>();

    /**
     * Canvas起始旋转角度
     */
    private static final int CANVAS_ROTATE_ANGLE = 60;

    /**
     * 动画当前状态
     */
    private int mStatus = STATUS_STILL;

    /**
     * Canvas旋转角度
     */
    private int mCanvasAngle;

    /**
     * 线条长度
     */
    private float mLineLength;

    /**
     * 半圆Y轴位置
     */
    private float mCircleY;

    /**
     * 第几步动画
     */
    private int mStep;

    public SlackLoadingElement(IComponentCallback componentCallback) {
        callback = componentCallback;
    }

    @Override
    public void initPaint() {
        super.initPaint();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        Color currentColor = new Color(mColors[0]);
        mPaint.setColor(currentColor);
        mPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);

        initData();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        mWidth = getWidth();
        mHeight = getHeight();
        switch (mStep % 4) {
            case 0:
                for (int i = 0; i < mColors.length; i++) {
                    mPaint.setColor(new Color(mColors[i]));
                    drawCRLC(canvas, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 - mLineLength, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mEntireLineLength, mPaint, mCanvasAngle + i * 90);
                }
                break;
            case 1:
                for (int i = 0; i < mColors.length; i++) {
                    mPaint.setColor(new Color(mColors[i]));
                    drawCR(canvas, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mEntireLineLength, mPaint, mCanvasAngle + i * 90);
                }

                break;

            case 2:
                for (int i = 0; i < mColors.length; i++) {
                    mPaint.setColor(new Color(mColors[i]));
                    drawCRCC(canvas, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mCircleY, mPaint, mCanvasAngle + i * 90);
                }

                break;

            case 3:
                for (int i = 0; i < mColors.length; i++) {
                    mPaint.setColor(new Color(mColors[i]));
                    drawLC(canvas, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mEntireLineLength, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mLineLength, mPaint, mCanvasAngle + i * 90);
                }
                break;
            default:
                break;
        }
    }

    @Override
    public ArrayList<Animator> onCreateAnimators() {
        return new ArrayList<>();
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    @Override
    public void startAnimators() {
        reset();
        start();
    }

    @Override
    public void stopAnimators() {
        reset();
    }

    @Override
    public void pauseAnimation() {
        //do nothing  because animation is not controlled by the parent class
    }

    @Override
    public void resumeAnimation() {
        //do nothing  because animation is not controlled by the parent class
    }

    @Override
    public void resetAnimation() {
        //do nothing  because animation is not controlled by the parent class
    }

    @Override
    public BaseAnimationController.IAnimationController initAnimationController() {
        return this;
    }

    private void drawCRLC(Canvas canvas, float startX, float startY, float stopX, float stopY, Paint paint, int rotate) {
        canvas.rotate(rotate, mWidth / 2, mHeight / 2);
        canvas.drawLine(startX, startY, stopX, stopY, paint);
        canvas.rotate(-rotate, mWidth / 2, mHeight / 2);
    }

    private void drawCR(Canvas canvas, float x, float y, Paint paint, int rotate) {
        canvas.rotate(rotate, mWidth / 2, mHeight / 2);
        canvas.drawCircle(x, y, mCircleRadius, paint);
        canvas.rotate(-rotate, mWidth / 2, mHeight / 2);
    }

    private void drawCRCC(Canvas canvas, float x, float y, Paint paint, int rotate) {
        canvas.rotate(rotate, mWidth / 2, mHeight / 2);
        canvas.drawCircle(x, y, mCircleRadius, paint);
        canvas.rotate(-rotate, mWidth / 2, mHeight / 2);
    }

    private void drawLC(Canvas canvas, float startX, float startY, float stopX, float stopY, Paint paint, int rotate) {
        canvas.rotate(rotate, mWidth / 2, mHeight / 2);
        canvas.drawLine(startX, startY, stopX, stopY, paint);
        canvas.rotate(-rotate, mWidth / 2, mHeight / 2);
    }

    /**
     * Animation1
     * 动画1
     * Canvas Rotate Line Change
     * 画布旋转及线条变化动画
     */

    private void startCRLCAnim() {
        Collection<Animator> animList = new ArrayList<>();
        AnimatorValue canvasRotateAnim = new AnimatorValue();

        canvasRotateAnim.setValueUpdateListener((animatorValue, v) -> mCanvasAngle = (int) (CANVAS_ROTATE_ANGLE + 360 * v));

        animList.add(canvasRotateAnim);


        AnimatorValue lineWidthAnim = new AnimatorValue();
        lineWidthAnim.setValueUpdateListener((animatorValue, v) -> {
            mLineLength = mEntireLineLength * Math.abs((1 - 2 * v));
            reflushComponent();
        });
        animList.add(lineWidthAnim);


        AnimatorGroup animatorGroup = new AnimatorGroup();
        animatorGroup.setDuration(mDuration);
        animatorGroup.runParallel(canvasRotateAnim, lineWidthAnim);
        animatorGroup.setCurveType(Animator.CurveType.LINEAR);
        animatorGroup.setStateChangedListener(new SimpleAnimatorListener() {
            @Override
            public void onEnd(Animator animator) {
                super.onEnd(animator);
                if (mStatus == STATUS_LOADING) {
                    mStep++;
                    startCRAnim();
                }
            }
        });
        animatorGroup.start();
        mAnimList.add(animatorGroup);

    }


    /**
     * Animation2
     * 动画2
     * Canvas Rotate
     * 画布旋转动画
     */
    private void startCRAnim() {
        AnimatorValue canvasRotateAnim = new AnimatorValue();
        canvasRotateAnim.setDuration(mDuration);
        canvasRotateAnim.setCurveType(Animator.CurveType.LINEAR);
        float angle = mCanvasAngle;
        canvasRotateAnim.setValueUpdateListener((animatorValue, v) -> {
            mCanvasAngle = (int) (angle + 180 * v);
            if (callback != null) {
                callback.reflushComponent();
            }
        });


        canvasRotateAnim.setStateChangedListener(new SimpleAnimatorListener() {
            @Override
            public void onEnd(Animator animator) {
                super.onEnd(animator);
                if (mStatus == STATUS_LOADING) {
                    mStep++;
                    startCRCCAnim();
                }
            }
        });
        canvasRotateAnim.start();
        mAnimList.add(canvasRotateAnim);
    }


    /**
     * Animation3
     * 动画3
     * Canvas Rotate Circle Change
     * 画布旋转圆圈变化动画
     */
    private void startCRCCAnim() {
        Collection<Animator> animList = new ArrayList<>();
        AnimatorValue canvasRotateAnim = new AnimatorValue();
        canvasRotateAnim.setValueUpdateListener((animatorValue, v) -> {
            mCanvasAngle = (int) (mCanvasAngle + 90 + 90 * v);
        });

        animList.add(canvasRotateAnim);
        AnimatorValue circleYAnim = new AnimatorValue();

        circleYAnim.setValueUpdateListener((animatorValue, v) -> {
            mCircleY = mEntireLineLength / 4 + Math.abs((1 - 2 * v) * (3 * mEntireLineLength / 4));
        });
        animList.add(circleYAnim);


        AnimatorGroup animationGroup = new AnimatorGroup();
        animationGroup.setDuration(mDuration);
        animationGroup.runParallel(canvasRotateAnim, circleYAnim);
        animationGroup.setCurveType(Animator.CurveType.LINEAR);
        animationGroup.setStateChangedListener(new SimpleAnimatorListener() {
            @Override
            public void onEnd(Animator animator) {
                super.onEnd(animator);
                if (mStatus == STATUS_LOADING) {
                    mStep++;
                    startLCAnim();
                }
            }
        });
        animationGroup.start();
        mAnimList.add(animationGroup);
    }

    /**
     * Animation4
     * 动画4
     * Line Change
     * 线条变化动画
     */
    private void startLCAnim() {

        AnimatorValue lineWidthAnim = new AnimatorValue();

        lineWidthAnim.setDuration(mDuration);

        lineWidthAnim.setCurveType(Animator.CurveType.LINEAR);
        lineWidthAnim.setValueUpdateListener((animatorValue, v) -> {
            mLineLength = (float) mEntireLineLength - 1 - (v * 2) * (mEntireLineLength * 2 + 0.5f);
            reflushComponent();
        });
        lineWidthAnim.setStateChangedListener(new SimpleAnimatorListener() {
            @Override
            public void onEnd(Animator animator) {
                super.onEnd(animator);
                if (mStatus == STATUS_LOADING) {
                    mStep++;
                    startCRLCAnim();
                }
            }
        });
        lineWidthAnim.start();
        mAnimList.add(lineWidthAnim);
    }

    private void initData() {
        mCanvasAngle = CANVAS_ROTATE_ANGLE;
        mLineLength = mEntireLineLength;
        mCircleRadius = mEntireLineLength / 5;
        mPaint.setStrokeWidth(mCircleRadius * 2);
        mStep = 0;
    }

    public void reset() {
        if (mStatus == STATUS_LOADING) {
            mStatus = STATUS_STILL;
            for (Animator anim : mAnimList) {
                anim.cancel();
            }
        }
        initData();
        reflushComponent();
    }

    public void start() {
        if (mStatus == STATUS_STILL) {
            mAnimList.clear();
            mStatus = STATUS_LOADING;
            startCRLCAnim();
        }
    }
}
